package com.wontube.smr.bo.sites.imdb;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.apache.ibatis.session.SqlSession;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.wontube.client.extension.utils.DateUtils;
import com.wontube.client.extension.utils.FileUtils;
import com.wontube.client.extension.utils.StringUtils;
import com.wontube.core.dao.mybatis.QueryExample;
import com.wontube.smr.bo.constants.SiteConstants;
import com.wontube.smr.client.model.po.Movie;
import com.wontube.smr.client.model.po.MovieGenre;
import com.wontube.smr.conf.SmrConfig;
import com.wontube.smr.dao.mapper.MovieGenreMapper;
import com.wontube.smr.dao.mapper.MovieMapper;
import com.wontube.smr.pub.DefaultDBHelper;

/**
 * www.imdb.com
 * @author LuoBiao(2012-7-10)
 *
 */
public final class ImdbObtainBO {
	private final static Logger logger = LoggerFactory.getLogger(ImdbObtainBO.class);		
	private final static String IMDBURL = "http://www.imdb.com";	
	private final static char[] param = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','#'};
	/** IMDB预告片URL */
	private final static String TRAILER_GALLERY_URL = "http://www.imdb.com/features/video/browse/trailer?c=";
	private final static int MAX_TRAILLER_TO_SAVE = 30;
	private final static String SAVE_IMAGE_PREFIX = "/images/sites/imdb/";
	private final static String DEFAULT_IMDB_IMAGE = "/images/default/imdb-default.jpg";
	
	private final static String IMAGE_SAVE_LOCATION = SmrConfig.SINGLE.getSitesImagePath() +  SAVE_IMAGE_PREFIX;
	//private final static String IMAGE_SAVE_LOCATION = "D:/workspace/smr/smr-web/src/main/webapp/images/sites/imdb/";
	
	private final static int CONNECT_READ_TIMEOUT = 30 * 1000;
	private final static String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1";
	private final static String REFERER = "http://www.imdb.com/";
	
	private ImdbObtainBO() {
	}
	
	/**
	 * 得到IMDB的所有预告片信息
	 * @return
	 * @throws Exception 
	 */
	public static int obtainTrailer() {	
		int count = 0;		
		for(int i=0; i<param.length; i++){
			String urlStr = TRAILER_GALLERY_URL + param[i];
			Document doc = ImdbObtainBO.getWebDocument(urlStr);
			if(doc == null){				
				continue;
			}
			
			count += obtainAndSaveTraillers(doc, count);
		}
		
		return count;
	}
	
	private static int obtainAndSaveTraillers(Document doc, int index) {
		List<Movie> trailerList = new ArrayList<Movie>();	
		int count = 0;
		Elements elements = doc.select("#main > div.article").eq(1).select("div.browse-video-column > ul > li");
		for(Element ele : elements){
			String absUrl = IMDBURL + ele.select("a").eq(0).attr("href");
			Movie trailer = null;
			try {
				trailer = grabTrailerDetail(absUrl);
			} catch (Exception e) {	
				logger.error("error happen when grab {} detail", absUrl, e);
			}
			
			if(trailer != null){
				
				trailerList.add(trailer);
			}
			
			int size = trailerList.size();
			if(size >= MAX_TRAILLER_TO_SAVE){
				count += saveTrailer(trailerList, count + index);			
				trailerList.clear();
			}
		}
		
		//the last one
		count += saveTrailer(trailerList, count + index);
		
		return count;		
	}
	
	/**
	 * 抓取预告片的详细信息
	 * @param absUrl
	 * @return
	 * @throws Exception
	 */
	private static Movie grabTrailerDetail(String absUrl) {	
		String url = absUrl + "/";
		Document doc = ImdbObtainBO.getWebDocument(url);		
		if(doc == null){			
			return null;
		}
		
		//得到预告片播放地址,没有播放地址的，不抓取
		String trailerURL = doc.select("#overview-bottom > a").eq(0).attr("href");
		if(trailerURL.isEmpty()){			
			return null;
		}
		
		//缩略图
		String img = doc.select("#img_primary > a > img").attr("src");
		if(img.isEmpty()){
			return null;
		}
		
		//发布时间
		String desc = null;
		Date publishTime = null;
		Elements txtBlock = doc.select("#maindetails_center_bottom > div.article");
		for (Element e : txtBlock) {
			String h2 = (e.select("h2").text().trim());
			if("Storyline".equals(h2)){
				Element el = e.select("p").first();
				if( el != null){
					desc = el.ownText().trim();
				}				
			}else if("Details".equals(h2)){
				Elements details = e.select("div.txt-block");
				for (Element element : details) {
					String h4 = (element.select("div.txt-block > h4 ").text()).trim();					
					if("Release Date:".equals(h4)){
						String datetime = element.select("time").attr("datetime");						
						publishTime = calReleaseDate(datetime);			
						
						break;
					}
				}				
			}
		}	
		
		if(publishTime == null){
			String time = doc.select("#overview-top > h1 > span").text().trim();
			if( ! time.isEmpty() && time.length() > 5){
				String year = time.substring(1, 5);
				SimpleDateFormat format = new SimpleDateFormat("yyyy");
				publishTime = DateUtils.parse(format, year);
			}			
		}		
		
		if(publishTime == null){
			return null;
		}
		
		if(desc == null){
			desc = doc.select("#overview-top > p").text();			
		}
		
		Movie movie = new Movie();
		String[] id_temp = absUrl.split("/");
		String vid = id_temp[id_temp.length-1];
		movie.setId(SiteConstants.ID_PREFIX_IMDB + vid);
		movie.setVideoId(vid);
		movie.setAllowEmbed(0);		
		movie.setMovieType(Movie.TYPE_TRAILER);
		movie.setWebsite(SiteConstants.WEBSITE_IMDB);		
		movie.setThumbnail(img);
		movie.setItemUrl(IMDBURL + trailerURL);		
		
		movie.setDescription(desc);
		movie.setPublishTime(publishTime);
		
		//预告片名字
		String trailerName = doc.select("#overview-top > h1").text();
		int index = trailerName.indexOf("(");
		if(index > 0){
			trailerName = trailerName.substring(0, index);
		}		
		
		//title and 首字母
		movie.setTitle(trailerName.trim());
		movie.setTitleInitial(StringUtils.getInitial(movie.getTitle()));
		
		//Genre
		Elements genreEles = doc.select("#overview-top > div.infobar > a");
		if( ! genreEles.isEmpty()) {
			StringBuilder sb = new StringBuilder();
			for (Element ele : genreEles) {
				String href = ele.attr("href");
				if(href.startsWith("/genre/")){
					sb.append(href.substring("/genre/".length()));
					sb.append(",");
				}
			}
			
			if(sb.length() > 0){				
				//修正genre			
				movie.setGenre(ImdbMovieGenres.remendAllGenres(sb.toString()));
			}			
		}	
		
		//得到评分
		String score = (doc.select("#overview-top > div.star-box > div.star-box-giga-star").text()).trim();		
		if( ! score.isEmpty()){			
			movie.setScore(BigDecimal.valueOf(Double.parseDouble(score)));			
		}
		
		//director and stars
		Elements infos = doc.select("#overview-top > div.txt-block");
		for (Element el : infos) {
			String h4 = el.select("h4").text().trim();
			if("Director:".equals(h4)){				
				movie.setDirector(el.select("a").text().trim());
			}else if("Directors:".equals(h4)){
				movie.setDirector(el.select("a").first().text().trim());
			} else if("Stars:".equals(h4)){
				Elements starsEls = el.select("a");
				StringBuilder sb = new StringBuilder();
				for (int i = 0; i < starsEls.size(); i++) {
					if(i != 0){
						sb.append(",");
					}
					sb.append(starsEls.get(i).text());
				}			
				movie.setActors(sb.toString());
			}
		}
		
		return movie;
	}
	
	private static Date calReleaseDate(String time) {		
		String[] times = time.split("-");		
		if(times != null){
			int len = times.length;
			if(len == 1){
				SimpleDateFormat format = new SimpleDateFormat("yyyy");
				return DateUtils.parse(format, time);
			}else if(len == 2){			
				SimpleDateFormat format = new SimpleDateFormat("yyyy-mm");
				return DateUtils.parse(format, time);
			}else if(len == 3){				
				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
				return DateUtils.parse(format, time);
			}
		}		
		return null;
	}
	
	/**
	 * 保存抓取到的预告片到数据库
	 * @param trailerList
	 * @return
	 * @throws Exception
	 */
	private static int saveTrailer(List<Movie> trailerList, int count) {				
		int index = count;
		SqlSession session = DefaultDBHelper.getBatchSqlSession();
		Date now = DateUtils.getNow();
		try {
			MovieMapper mapper = session.getMapper(MovieMapper.class);
			MovieGenreMapper genreMapper = session.getMapper(MovieGenreMapper.class);
			for (Movie trailer : trailerList) {								
				trailer.setVersion(now);
				String trailerId = trailer.getId();					
				Movie tmpMovie = mapper.selectByPrimaryKey(trailerId);			
				if(tmpMovie != null){
					//不考虑已有数据
					continue;
				}				
				
				boolean inserted = false;
				//可能跟moviefone重复
				QueryExample ex = new QueryExample();
				ex.or().addCriterion("title=", trailer.getTitle())
						.addCriterion("movie_type=", Movie.TYPE_TRAILER);
				if(mapper.countByExample(ex) == 0){
					//拉取image, imdb有防盗链
					boolean fetch = fetchImdbImage(trailer);
					if(fetch){
						trailer.setThumbnail(SAVE_IMAGE_PREFIX + trailer.getTitleInitial() + "/" + trailerId + ".jpg");
					}else{
						trailer.setThumbnail(DEFAULT_IMDB_IMAGE);
					}							
					//insert
					trailer.setSortIndex(++index);
					mapper.insert(trailer);
					inserted = true;
				}	
				
				if(inserted){
					//考虑genre问题
					String genreNames = trailer.getGenre();
					if( ! StringUtils.isNullOrEmpty(genreNames)){		
						String[] genres = genreNames.split(",");
						for (String genre : genres) {
							QueryExample gex = new QueryExample();
							gex.or().addCriterion("movie_genre.movie_id=", trailerId)
									.addCriterion("movie_genre.genre_name=", genre);
							
							if(genreMapper.countByExample(gex) == 0){
								//增加关联
								MovieGenre movieGenre = new MovieGenre();
								movieGenre.setId(UUID.randomUUID().toString());
								movieGenre.setMovieId(trailerId);
								movieGenre.setGenreName(genre);
								genreMapper.insert(movieGenre);
							}
						}					
					}	
				}										
			}
			
			session.commit();
		} finally {
			session.close();
		}			
		
		return index;
	}
	
	private static boolean fetchImdbImage(Movie movie) {
		String url = movie.getThumbnail();		
		File file = new File(IMAGE_SAVE_LOCATION + movie.getTitleInitial() + "/" + movie.getId() + ".jpg");	
		if(file.exists()){
			return true;
		}
		try {
			return FileUtils.fetchAndSave(url, file);
		} catch (IOException e) {
			return false;
		}
	}

	/**
	 * 拉取页面, 并将HTML内容转换成Document
	 * @return
	 * @throws IOException 
	 */
	private static Document getWebDocument(String url) {
		try {
			return Jsoup.connect(url).timeout(CONNECT_READ_TIMEOUT).userAgent(USER_AGENT).referrer(REFERER).get();
		} catch (IOException e) {			
			logger.error(e.toString());
		}
		return null;
	}
	
	public static void main(String[] args) {	
		obtainTrailer();		
	}
}
